#include <iostream>
#include <vector>
#include <termios.h>

using namespace std;

const int KEYCODE_BACKSPACE = 127, KEYCODE_EXIT = 4;
const string op = "+-*/.", bracket = "()",
        COLOR_DEFAULT = "\033[0m", COLOR_RED = "\033[31m";
vector<int> left_bracket, right_bracket;
vector<vector<int>> bracket_pair;
vector<bool> l_bracket_ok, r_bracket_ok;

vector<int> operator_idx;
vector<bool> operator_ok, operator_checked;

vector<int> dot_idx;
vector<bool> dot_ok;

struct bracket_check_result {
    bool is_pairing_ok = true;
    bool is_operator_ok = true;
    bool is_operator_missing = false;
};

bracket_check_result bracket_check(const string &target);

bool operator_check(const string &target);

bool dot_check(const string &target);

int getch();

int main() {
    string s = "1.2", result;
    auto bad_cha_err = false, bad_bracket_err = false, bad_operator_err = false,
            empty_bracket_err = false, dot_check_err = false, operator_missing_err = false;
    bracket_check(s);
    operator_check(s);
    dot_check(s);
    while (true) {
        system("clear");
        // custom format text with colour
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == '(') {
                for (int j = 0; j < left_bracket.size(); ++j) {
                    if (left_bracket[j] == i) {
                        if (!l_bracket_ok[j]) {
                            cout << COLOR_RED + s[i];
                        } else {
                            cout << COLOR_DEFAULT + s[i];
                        }
                    }
                }
            } else if (s[i] == ')') {
                for (int j = 0; j < right_bracket.size(); ++j) {
                    if (right_bracket[j] == i) {
                        if (!r_bracket_ok[j]) {
                            cout << COLOR_RED + s[i];
                        } else {
                            cout << COLOR_DEFAULT + s[i];
                        }
                    }
                }
            } else if (op.contains(s[i]) or (!dot_check_err and s[i] == '.')) {
                auto pos = -1;
                for (int j = 0; j < operator_idx.size(); ++j) {
                    if (operator_idx[j] == i) {
                        pos = j;
                        break;
                    }
                }
                if (pos == -1 or operator_ok[pos]) {
                    cout << COLOR_DEFAULT + s[i];
                } else {
                    cout << COLOR_RED + s[i];
                }
            } else if (s[i] == '.') {
                for (int j = 0; j < dot_idx.size(); ++j) {
                    if (dot_idx[j] == i) {
                        if (dot_ok[j])
                            cout << COLOR_DEFAULT + s[i];
                        else
                            cout << COLOR_RED + s[i];
                    }
                }
            } else {
                cout << COLOR_DEFAULT + s[i];
            }
        }
        cout << COLOR_DEFAULT + " = " << result << endl;
        if (bad_cha_err) {
            cout << COLOR_RED + "[!] 输入字符不合法" << endl;
            bad_cha_err = false;
        }
        if (bad_bracket_err) {
            cout << COLOR_RED + "[!] 括号匹配有错误" << endl;
            bad_cha_err = false;
        }
        if (bad_operator_err) {
            cout << COLOR_RED + "[!] 运算符号或小数点前后没有数字" << endl;
            bad_operator_err = false;
        }
        if (empty_bracket_err) {
            cout << COLOR_RED + "[!] 括号中表达式不得为空" << endl;
        }
        if (dot_check_err) {
            cout << COLOR_RED + "[!] 一个数字中只能有一个小数点" << endl;
        }
        if (operator_missing_err) {
            cout << COLOR_RED + "[!] 两括号间缺少运算符" << endl;
        }
        auto ch_num = getch();
        auto ch = char(ch_num);
        if ((ch >= '0' and ch <= '9') or op.contains(ch) or bracket.contains(ch) or ch == '.') {
            s += ch;
        } else if (ch_num == KEYCODE_BACKSPACE) {
            if (!s.empty()) {
                s.pop_back();
            }
        } else if (ch_num == KEYCODE_EXIT) {
            break;
        } else {
            bad_cha_err = true;
        }
        bracket_check_result BCResult = bracket_check(s);
        bad_bracket_err = !BCResult.is_pairing_ok;
        empty_bracket_err = !BCResult.is_operator_ok;
        operator_missing_err = BCResult.is_operator_missing;
        dot_check_err = !dot_check(s);
        if (!bad_bracket_err and !dot_check_err) {
            bad_operator_err = !operator_check(s);
        }
    }
    return 0;
}

bool dot_check(const string &target) {
    auto o = true;
    auto dot = 0;
    dot_idx.clear();
    dot_ok.clear();
    for (int i = 0; i < target.size(); ++i) {
        if (target[i] == '.') {
            dot += 1;
            dot_idx.push_back(i);
            dot_ok.push_back(dot <= 1);
        }
        if (op.contains(target[i]) or bracket.contains(target[i])) {
            // set result
            if (dot > 1) {
                o = false;
            }
            // reset
            dot = 0;
        }
    }
    // set result
    if (dot > 1) {
        o = false;
    }
    return o;
}

bool operator_check(const string &target) {
    auto o = true;
    operator_idx.clear();
    operator_checked.clear();
    operator_ok.clear();
    for (int i = 0; i < target.size(); ++i) {
        if (op.contains(target[i])) {
            operator_idx.push_back(i);
            operator_checked.push_back(false);
            operator_ok.push_back(false);
        }
    }

    //DEBUG
    for(auto &i: bracket_pair) {
        cout << i[0] << i[1] << endl;
    }

    for (auto &i: bracket_pair) {
        for (int j = i[0] + 1; j < i[1]; ++j) {
            if (op.contains(target[j])) {
                auto pos = -1;
                for (int k = 0; k < operator_idx.size(); ++k) {
                    if (operator_idx[k] == j) {
                        pos = k;
                        break;
                    }
                }
                if (!operator_checked[pos]) {
                    // do check
                    operator_ok[pos] = operator_idx[pos] != i[0] + 1 and operator_idx[pos] != i[1] - 1
                                       and !op.contains(target[operator_idx[pos] + 1])
                                       and !op.contains(target[operator_idx[pos] - 1]);
                    if (!operator_ok[pos]) {
                        o = false;
                    }
                    operator_checked[pos] = true;
                }
            }
        }
    }
    return o;
}

bracket_check_result bracket_check(const string &target) {
    bracket_check_result result;
    left_bracket.clear();
    right_bracket.clear();
    bracket_pair.clear();
    l_bracket_ok.clear();
    r_bracket_ok.clear();
    for (int i = 0; i < target.size(); ++i) {
        if (target[i] == '(') {
            left_bracket.push_back(i);
            l_bracket_ok.push_back(false);
        } else if (target[i] == ')') {
            right_bracket.push_back(i);
            r_bracket_ok.push_back(false);
        }
    }
    for (int i = (int) left_bracket.size() - 1; i >= 0; --i) {
        if (!l_bracket_ok.at(i)) {
            auto flag = false;
            for (int j = left_bracket[i] + 1; j < target.size(); ++j) {
                if (target[j] == ')') {
                    for (int k = 0; k < right_bracket.size(); ++k) {
                        if (right_bracket[k] == j and !r_bracket_ok[k]) {
                            r_bracket_ok[k] = true;
                            l_bracket_ok[i] = true;
                            vector<int> data;
                            data.push_back(left_bracket[i]);
                            data.push_back(right_bracket[k]);
                            bracket_pair.push_back(data);
                            flag = true;
                            break;
                        }
                    }
                    if (flag) {
                        break;
                    }
                }
            }
            if (!flag) {
                result.is_pairing_ok = false;
            }
        }
    }
    for (auto i: bracket_pair) {
        if (i[0] + 1 == i[1]) {
            result.is_operator_ok = false;
            for (int j = 0; j < left_bracket.size(); ++j) {
                if (left_bracket[j] == i[0]) {
                    l_bracket_ok[j] = false;
                }
                if (right_bracket[j] == i[1]) {
                    r_bracket_ok[j] = false;
                }
            }
        }
    }

    for(int i = 0; i < right_bracket.size(); i++) {
        for (int j = 0; j < left_bracket.size(); j++) {
            if (right_bracket[i] + 1 == left_bracket[j]) {
                r_bracket_ok[i] = false;
                l_bracket_ok[j] = false;
                result.is_operator_missing = true;
            }
        }
    }

    vector<int> data;
    data.push_back(-1);
    data.push_back((int) target.size());
    bracket_pair.push_back(data);
    return result;
}

int getch() {
    struct termios tm{}, tm_old{};
    int fd = 0, ch;

    if (tcgetattr(fd, &tm) < 0) {//保存现在的终端设置
        return -1;
    }

    tm_old = tm;
    cfmakeraw(&tm);//更改终端设置为原始模式，该模式下所有的输入数据以字节为单位被处理
    if (tcsetattr(fd, TCSANOW, &tm) < 0) {//设置上更改之后的设置
        return -1;
    }

    ch = getchar();
    if (tcsetattr(fd, TCSANOW, &tm_old) < 0) {//更改设置为最初的样子
        return -1;
    }

    return ch;
}
